package cn.caskm.souvenirshopsystem.service.impl;

import cn.caskm.souvenirshopsystem.config.JwtProperties;
import cn.caskm.souvenirshopsystem.constants.BizConstants;
import cn.caskm.souvenirshopsystem.domain.Result;
import cn.caskm.souvenirshopsystem.domain.dto.PageDTO;
import cn.caskm.souvenirshopsystem.domain.dto.UpdatePasswordFormDTO;
import cn.caskm.souvenirshopsystem.domain.po.AdminUser;
import cn.caskm.souvenirshopsystem.domain.query.AdminUserListQuery;
import cn.caskm.souvenirshopsystem.domain.vo.AdminUserVO;
import cn.caskm.souvenirshopsystem.enums.StatusEnum;
import cn.caskm.souvenirshopsystem.exceptions.BizException;
import cn.caskm.souvenirshopsystem.mapper.AdminUserMapper;
import cn.caskm.souvenirshopsystem.service.AdminUserService;
import cn.caskm.souvenirshopsystem.utils.JwtUtil;
import cn.caskm.souvenirshopsystem.utils.MD5Util;
import cn.caskm.souvenirshopsystem.utils.UserContext;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class AdminUserServiceImpl extends ServiceImpl<AdminUserMapper, AdminUser> implements AdminUserService {

    private final JwtProperties jwtProperties;

    @Override
    public Result<String> login(String userName, String password) {
        // 校验用户名密码是否为空
        if (StrUtil.hasBlank(userName, password)) {
            throw new BizException("用户名或密码不能为空");
        }

        // 查询登录用户
        AdminUser user = lambdaQuery().eq(AdminUser::getUserName, userName).one();
        if (user == null) {
            throw new BizException("用户不存在");
        }

        // 校验是否启用账户
        if (user.getStatus() == StatusEnum.OFF) {
            throw new BizException("账号已停用");
        }

        // 校验密码
        String saltPassword = MD5Util.encodeWithSalt(password, user.getSalt());
        if (!saltPassword.equals(user.getPassword())) {
            throw new BizException("密码错误");
        }

        // 生成JWT token
        Map<String, Object> map = new HashMap<>();
        map.put(BizConstants.USER_INFO, user.getId());
        String token = JwtUtil.createToken(map, jwtProperties.getPrivateKey(), jwtProperties.getTokenTTL());

        // 返回
        return Result.success(token);
    }

    @Override
    public Result<PageDTO<AdminUserVO>> adminList(AdminUserListQuery query) {
        // 获取参数
        Long pageNum = query.getPageNum();
        if (pageNum == null) {
            pageNum = BizConstants.DEFAULT_PAGE_NUM;
        }
        Long pageSize = query.getPageSize();
        if (pageSize == null) {
            pageSize = BizConstants.DEFAULT_PAGE_SIZE;
        }
        String userName = query.getUserName();
        String phone = query.getPhone();

        // 查询数据
        Page<AdminUser> page = lambdaQuery()
                .like(StrUtil.isNotBlank(userName), AdminUser::getUserName, userName)
                .like(StrUtil.isNotBlank(phone), AdminUser::getPhone, phone)
                .orderByDesc(AdminUser::getCreateTime)
                .page(new Page<>(pageNum, pageSize));
        List<AdminUser> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return Result.success(PageDTO.empty());
        }

        // 转换vo返回
        List<AdminUserVO> list = BeanUtil.copyToList(records, AdminUserVO.class);
        return Result.success(PageDTO.of(list, page.getPages(), page.getTotal()));
    }

    @Override
    public Result<AdminUserVO> detail(Long id) {
        AdminUser user = getById(id);
        if (user == null) {
            throw new BizException("用户信息为空");
        }

        // 转换vo返回
        return Result.success(BeanUtil.toBean(user, AdminUserVO.class));
    }

    @Override
    public void saveOrUpdateUser(AdminUser user) {
        // 分别处理新增和修改
        if (user.getId() == null) {
            // 校验信息是否重复
            checkDuplicate(user, null);

            // 生成随机盐
            String salt = RandomUtil.randomNumbers(BizConstants.SALT_LEN);
            user.setSalt(salt);
            //加密密码
            user.setPassword(MD5Util.encodeWithSalt(user.getPassword(), salt));
            // 保存用户
            user.setCreateTime(LocalDateTime.now());
            save(user);
        } else {
            // 校验信息信息是否重复
            AdminUser currentUser = getById(user.getId());
            checkDuplicate(user, currentUser);

            // 更新信息
            user.setUpdateTime(LocalDateTime.now());
            updateById(user);
        }
    }

    private void checkDuplicate(AdminUser user, AdminUser currentUser) {
        String userName = user.getUserName();
        // 校验用户名是否重复
        Long count = lambdaQuery()
                .eq(StrUtil.isNotBlank(userName), AdminUser::getUserName, userName)
                .ne(currentUser != null, AdminUser::getId, user.getId())
                .count();
        if (count > 0) {
            throw new BizException("用户名重复");
        }
        // 校验手机号
        String phone = user.getPhone();
        count = lambdaQuery()
                .eq(StrUtil.isNotBlank(phone), AdminUser::getPhone, phone)
                .ne(currentUser != null, AdminUser::getId, user.getId())
                .count();
        if (count > 0) {
            throw new BizException("手机号重复");
        }
    }

    @Override
    public Result<AdminUserVO> getLoginUserInfo() {
        // 获取登录用户
        Long userId = UserContext.getUser();

        // 查询用户
        AdminUser user = getById(userId);

        // 转换返回
        return Result.success(BeanUtil.toBean(user, AdminUserVO.class));
    }

    @Override
    public void updatePassword(UpdatePasswordFormDTO body) {
        // 获取参数
        String oldPassword = body.getOldPassword();
        String newPassword = body.getNewPassword();
        String confirmNewPassword = body.getConfirmNewPassword();

        // 获取登录用户
        Long userId = UserContext.getUser();
        AdminUser user = getById(userId);

        // 校验旧密码是否相同
        String oldSaltPassword = MD5Util.encodeWithSalt(oldPassword, user.getSalt());
        if (!oldSaltPassword.equals(user.getPassword())) {
            throw new BizException("旧密码错误");
        }

        // 判断两个新密码是否相同
        if (!newPassword.equals(confirmNewPassword)) {
            throw new BizException("两次新密码输入不同");
        }

        // 重新设置密码
        user.setPassword(MD5Util.encodeWithSalt(newPassword, user.getSalt()));
        // 更新用户
        updateById(user);
    }
}
